﻿#include "server_base.h"
#include "retcodes.h"
#include "MiniDump.h"
#include "string_common.h"
#include "server_net.h"
#include <thread>
#include "GameHostManager.h"
#include "base.h"
#include "time_module.h"
#ifdef _MSC_VER
#include <corecrt_io.h>
#include <direct.h>
#endif

#include "log.h"
#include "performance.h"
#include "timer.h"
#include "net_event_manager.h"


class CPerfLogTimer : public ::common::CTimer
{
public:
	void TimerActive()
	{
		PERF_LOG;
		TimerStart();
	}
};


int MAKEDIR(const char* dirname, int limit)
{
#ifdef _MSC_VER
	return _mkdir(dirname);
#else
	return mkdir(dirname, limit);
#endif
}

int ACCESS(const char* dirname, int var)
{
#ifdef _MSC_VER
	return _access(dirname, var);
#else
	return access(dirname, var);
#endif
}


static volatile bool signal_user1_asked = false;
static volatile bool signal_user2_asked = false;

#ifndef _MSC_VER
static void SigHandler(int signal_val)
{
	signal(signal_val, SigHandler);
	if (signal_val == SIGUSR1)
	{
		signal_user1_asked = true;
	}
	else if (signal_val == SIGUSR2)
	{
		signal_user2_asked = true;
	}
}

static void Initsignal()
{
	signal(SIGHUP, SIG_IGN);
	signal(SIGINT, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);
	signal(SIGILL, SIG_IGN);
	signal(SIGTRAP, SIG_IGN);
	signal(SIGABRT, SIG_IGN);
	signal(SIGFPE, SIG_IGN);
	signal(SIGSEGV, SIG_IGN);
	signal(SIGPIPE, SIG_IGN);
	signal(SIGALRM, SIG_IGN);
	signal(SIGTERM, SIG_IGN);
	signal(SIGCHLD, SIG_IGN);
	signal(SIGCONT, SIG_IGN);
	signal(SIGTSTP, SIG_IGN);
	signal(SIGTTIN, SIG_IGN);
	signal(SIGTTOU, SIG_IGN);
	signal(SIGUSR1, SigHandler);
	signal(SIGUSR2, SigHandler);
}
#else
// Windows Ctr+C 处理函数
BOOL WINAPI HandlerRoutine_CtrlC(DWORD dwCtrlType)
{
	if (dwCtrlType == CTRL_C_EVENT)
	{
		signal_user1_asked = true;
		return TRUE;
	}
	return FALSE;
}

static bool bSetCtrlCHandle = false;
void SetCtrlCHandle(bool bAdd)
{
	if (bAdd)
	{
		if (!bSetCtrlCHandle)
		{
			bSetCtrlCHandle = true;
			SetConsoleCtrlHandler((PHANDLER_ROUTINE)HandlerRoutine_CtrlC, TRUE);
		}
	}
	else
	{
		if (bSetCtrlCHandle)
		{
			bSetCtrlCHandle = false;
			SetConsoleCtrlHandler((PHANDLER_ROUTINE)HandlerRoutine_CtrlC, FALSE);
		}
	}
}
#endif

IService::IService()
	: m_queue_socket(8192)
	, m_queue_server_socket(8192)
{
	exit_code_ = ::common::SUCCEED;
	service_status_ = SERVICE_INIT;
	service_id_ = 0;
	tick_time_ = 0;
	max_client_count_ = 1024;
}

int32_t IService::ServiceMain(int32_t argc, char** argv)
{
#ifndef _MSC_VER
	int opt = EOF;
	while ((opt = getopt(argc, argv, "vc:n:ef:s:")) != EOF)
	{
		switch (opt)
		{
		case 'v':
#ifdef _DEBUG_
			printf("service type %d id %d Debug build time : %s %s\n", GetServiceType(), GetServiceID(), __DATE__,
				__TIME__);
#else
			printf("service type %d id %d Release build time : %s %s\n", GetServiceType(), GetServiceID(), __DATE__,
				__TIME__);
#endif
			return ::common::SUCCEED;
		default:
			break;
		}
	}
#endif

	Json::Value v = ReadJsonFile("config/HostsConfig.json");
	if (v == Json::nullValue)
	{
		LOG_ERROR("default","ERROR: config/HostsConfig.json IS NULL!");
		system("pause");
		exit(1);
		return -1;
	}

	int32_t ret = GameHostManager::GetInstance().initialize();
	if ( ret != ::common::SUCCEED )
	{
		LOG_ERROR("default","ERROR: init host config err %d", ret);
		exit(1);
		return -1;
	}

	uint32_t traceLevel = v["traceLevel"].asUInt();
	// 初始化日志模块
	//initLog(traceLevel);

	LOG_DEBUG("default","argc=%d", argc);
	for (int i = 0; i<argc; ++i)
	{
		LOG_DEBUG("default","argv[%d]=%s", i, argv[i]);
	}

	//LOG_DEBUG("default", "_WIN32_WINNT=%8X", _WIN32_WINNT);

	const char* kLogRootDir = "log";
	if ((ACCESS(kLogRootDir, 0) == -1) &&
		(MAKEDIR(kLogRootDir, 0777) != 0))
	{
		printf("creat log root dir[%s] failed \n", kLogRootDir);
		return -1;
	}
	std::string service_name = server_name_map_[GetServiceType()];
	service_log_dir_ = std::string(kLogRootDir) + "/" + service_name;
	if ((ACCESS(service_log_dir_.c_str(), 0) == -1) &&
		(MAKEDIR(service_log_dir_.c_str(), 0777) != 0))
	{
		printf("create service log dir failed : %s\n", service_log_dir_.c_str());
		return -1;
	}
	std::string service_log_path = service_log_dir_ + "/" + service_name + ".log";
	//初始日志模块；
	INIT_ROLLINGFILE_LOG("default", service_log_path.c_str(), common::LEVEL_DEBUG);
	std::string perf_log_path = service_log_dir_ + "/perf.log";
	//初始化性能统计日志模块;
	INIT_ROLLINGFILE_LOG("Perf", perf_log_path.c_str(), common::LEVEL_DEBUG);

	SetServiceStatus(SERVICE_INIT);

	//初始化信号量;
#ifdef _MSC_VER
	SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
#else
	Initsignal();
#endif

	::common::SetUTCAndLocalDiff();

	//初始化网络模块
	int32_t retcode = ::common::net::CNetEventManager::GetInstance().Startup(max_client_count_);
	if (retcode != ::common::SUCCEED)
	{
		LOG_ERROR("default", "[boot],ret_code:%d, startup network failed.", retcode);
		return retcode;
	}

	tick_time_ = ::common::GetCurrentMillisecond();
	::common::CTimeModule::GetInstance().Initialize(tick_time_);
	

	//逻辑初始化;
	retcode = Initialize();
	if (retcode != ::common::SUCCEED)
	{
		LOG_ERROR("default","[boot],ret_code:%d, Initialize failed.", retcode);
		return retcode;
	}

	//启动网络模块;
	pump_.start_service( 1);
	//pump_.start_service ( std::max( int( 1 ), int( std::thread::hardware_concurrency() )  ) );

	// 主线程先休眠1秒,让网络模块启动
	std::this_thread::sleep_for(std::chrono::milliseconds(1000));


	LOG_INFO("default", "Initialized succeed!");

#if defined (_MSC_VER) || defined (__CYGWIN__)
	printf("\n\
游戏服务器初始化完成 !!! 游戏开始 ...\n\
允许登录 ... ...\n\n\
输入 'cls'\t: 清除屏幕。\n\
输入 'quit'\t: 关闭服务器。\n\n");
#else
	LOG_INFO("default", "\n\n游戏服务器初始化完成 !!! 游戏开始 ...");
#endif

	CPerfLogTimer timer;
	timer.TimerInit(30 * 1000);
	timer.TimerStart();

	ServerStart();
	SetServiceStatus(SERVICE_ISRUNNING);
	ServiceLogic();

	timer.TimerStop();
	SetServiceStatus(SERVICE_FINAL);

	::common::CTimeModule::GetInstance().Finalize();
	// ::common::CTimeModule::ReleaseInstance();  // 单件模块必须最后释放

	::common::net::CNetEventManager::GetInstance().Shutdown();
	::common::net::CNetEventManager::ReleaseInstance();

	// 主线程先休眠5秒,让网络模块处理一下剩余的发送
	std::this_thread::sleep_for(std::chrono::milliseconds(5000));
	pump_.stop_service();

	Finalize();

	PERF_LOG;
	LOG_SHUTDOWN("Perf");
	LOG_SHUTDOWN("default");
	LOG_SHUTDOWN_ALL;
	return 0;
}

#define QUIT_COMMAND	"quit"
#define RESTART_COMMAND	"restart"
#define LIST_ALL_CLIENT	"list_all"
#define LIST_STATUS		"status"
#define KICK_ALL		"kick_all"
#define RELOAD			"reload"
#define CLEAR			"cls"
#define KICKOUT			"kickout"


//字符串分割函数  
std::vector<std::string> split(std::string str, std::string pattern)
{
	uint32_t pos;
	std::vector<std::string> result;
	str += pattern;//扩展字符串以方便操作  
	uint32_t size = (uint32_t)(str.size());

	for (uint32_t i = 0; i < size; ++i )
	{
		pos = (uint32_t)(str.find(pattern, i));
		if (pos < size)
		{
			std::string s = str.substr(i, pos - i);
			result.push_back(s);
			i = pos + (uint32_t)(pattern.size()) - 1;
		}
	}
	return result;
}

int32_t IService::ServiceLogic()
{
	bool isBusy = false;
	int64_t cycleTime = 0;
	
	while (exit_code_ == 0)
	{
		int64_t cur_ms = ::common::GetCurrentMillisecond();
		if (cur_ms < tick_time_)
		{
			//添加保护，防止由于修改时间带来主循环无法继续;
			tick_time_ = cur_ms;
		}
		int64_t next_tick_ms = tick_time_ + 50;

		int64_t tick = (next_tick_ms - cur_ms) < 0 ? 1 : 5;
		::common::net::CNetEventManager::GetInstance().OnUpdate(tick);
		//processSocketMessage();
		//processServerSocketMessage();

		// 小于50毫秒 内执行过的  contiune 执行消息
		if (cur_ms < next_tick_ms)
		{
			continue;
		}
		cycleTime = ::common::GetCurrentMillisecond() - tick_time_;
		isBusy = (cycleTime > 60) ? true : false;
		if (isBusy) {
			LOG_ERROR("default", "process too long [%d]", cycleTime);
		}
		tick_time_ = cur_ms;

		PERF_BEGIN(TimerTickUpdate);
		::common::CTimeModule::GetInstance().TickUpdate(tick_time_);
		PERF_END(TimerTickUpdate);

		if (signal_user2_asked == true)
		{
			OnUserSignal2();
			signal_user2_asked = false;
		}
		if (signal_user1_asked == true)
		{
			//信号一为退出信号;	
			OnUserSignal1();
			signal_user1_asked = false;
		}

		PERF_BEGIN(ServiceMainLoop );
		ServiceMainLoop();
		PERF_END(ServiceMainLoop);

		PERF_BEGIN(TickUpdate);
		TickUpdate();
		PERF_END(TickUpdate);

		if (exit_code_ != 0)
		{
			LOG_ERROR("default","exit process for [%d]", exit_code_);
		}
	}

	return ::common::SUCCEED;
}

int32_t IService::Exit(int32_t exit_code)
{
	exit_code_ = exit_code;
	return ::common::SUCCEED;
}

EServiceStatus IService::GetServiceStatus() const
{
	return service_status_;
}

EServiceStatus IService::SetServiceStatus(EServiceStatus service_status)
{
	if (service_status == service_status_) return service_status_;
	service_status_ = service_status;
	if (service_status_ == SERVICE_ISRUNNING)
	{
		LOG_INFO("default", "Service [ type %d, id %d ] startup success", GetServiceType(), GetServiceID());
	}
	else if (service_status_ == SERVICE_EXIT)
	{
		LOG_INFO("default", "Service [ type %d, id %d ] exit success", GetServiceType(), GetServiceID());
	}
	else if (service_status_ == SERVICE_FINAL)
	{
		LOG_INFO("default", "Service [ type %d, id %d ] final, begin exit", GetServiceType(), GetServiceID());
	}
	else if (service_status_ == SERVICE_INIT)
	{
		LOG_INFO("default", "Service [ type %d, id %d ] init, begin start", GetServiceType(), GetServiceID());
	}

	return service_status_;
}

void IService::OnUserSignal1()
{
	SetServiceStatus(SERVICE_WAITTING_EXIT);
	Exit(::common::ESERVICE_SIGNAL_USR1_ASKED);
}


int32_t IService::AddClientMsg(uint32_t socketId, uint32_t msgId, std::string &msg)
{
	CClientSocketMsg client_msg;
	client_msg.SetMsg(msg, socketId, msgId);
	AddClientMsgPtr(client_msg);
	return 0;
}

int32_t IService::AddServerMsg(uint32_t msgId, std::string &msg, const common::CProxyHead& head)
{
	CProxySocketMsg server_msg;
	server_msg.SetMsg(head, msg, 0);
	AddServerMsgPtr(server_msg);
	return 0;
}

void IService::ProcessServerMsg(CProxySocketMsg& val)
{
	LOG_DEBUG("default"," process socket msg %d processed Begin =====", val.head_.msg_id);

	CJsonMessageBase msg;
	bool ret = msg.ParseAcceptJson(val.msg_);
	if (ret == false)
	{
		LOG_ERROR("default","msg parse err!  msgid[%d][%s]", val.head_.msg_id, val.msg_.c_str());
		return;
	}
	msg.set_from_socket_id(val.fd_);

	ProxyMsgProcess process = GetProxyMsgFactory().GetMsgProcess(val.head_.msg_id);
	if (process == NULL)
	{
		LOG_ERROR("default","process is null! msgid[%u]", val.head_.msg_id);
		return;
	}

	process(val.head_, msg);

	LOG_DEBUG("default"," process socket msg %d processed OK =====", val.head_.msg_id);
}

void IService::AddClientMsgPtr(CClientSocketMsg& val)
{

	//LOG_DEBUG("default","Recv Client msgId: 0x%04X(%u) len %d", val->m_protocol_number, val->m_protocol_number, val->m_msg_size);

	if (m_queue_socket.IsFull())
	{
		LOG_ERROR("default","m_queue_socket.IsFull() : %d", (uint32_t)(m_queue_socket.Count()));
	}

	LOG_INFO("default","check m_queue_socket.Count() : %d", (uint32_t)(m_queue_socket.Count()));
	// socket阻塞了，需要报警
	uint32_t count = (uint32_t)(m_queue_socket.Count());
	if (count > 5000)
	{
		LOG_ERROR("default","error m_queue_socket.Count() : %u", count);
	}

	m_queue_socket.Put(val);
}

void IService::AddServerMsgPtr(CProxySocketMsg& val)
{
	m_queue_server_socket.Put(val);
	uint32_t count = (uint32_t)(m_queue_server_socket.Count());
	if (count > 5000)
	{
		LOG_ERROR("default", "error m_queue_server_socket.Count() : %u", count);
	}
}

void IService::processSocketMessage()
{
	_safe_guard_begin;

	std::deque<CClientSocketMsg> _socket;
	_socket.clear();

	m_queue_socket.Take(_socket);
	if (!_socket.empty())
	{
		uint32_t _count = (uint32_t)(_socket.size());
		LOG_DEBUG("default","socket msg count ----------------> %d", _count);
		for (uint32_t i = 0; i < _count; ++i)
		{
			auto _tmp = _socket.front();
			_socket.pop_front();
			ProcessClientMsg(_tmp);
			_tmp.clear();
		}
	}

	_safe_guard_end;
}

void IService::processServerSocketMessage()
{
	_safe_guard_begin;

	std::deque<CProxySocketMsg> _socket;
	_socket.clear();

	m_queue_server_socket.Take(_socket);
	if (!_socket.empty())
	{
		uint32_t _count = (uint32_t)(_socket.size());
		LOG_DEBUG("default","socket msg count ----------------> %d", _count);
		for (uint32_t i = 0; i < _count; ++i)
		{
			auto _tmp = _socket.front();
			_socket.pop_front();
			ProcessServerMsg(_tmp);
			_tmp.clear();
		}
	}

	_safe_guard_end;
}

void IService::OnUserSignal2()
{
	
}
